﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using HiUpdateTools.Core;
using Ionic.Zip;
using System.Net;

namespace HiUpdateTools.Client.Win
{
    public partial class UpdateForm : Form
    {
        private bool IsBusy;
        public UpdateForm()
        {
            InitializeComponent();

        }
        public void RunOnUiThread(System.Action action)
        {

            if (this.InvokeRequired)
            {
                this.Invoke(action);
            }
            else
            {
                action();
            }



        }
        void Copy(string sourceDir, string targetDir)
        {

            if (!Directory.Exists(targetDir))
                Directory.CreateDirectory(targetDir);

            ///Remove old tmp file 
            Directory.GetFiles(targetDir, "*.tmp").ToList().ForEach(file => File.Delete(file));
            Directory.GetFiles(targetDir, "*.PendingOverwrite").ToList().ForEach(file => File.Delete(file));

            foreach (var file in Directory.GetFiles(sourceDir))
            {
                if (file.IndexOf(".deploy") > -1)
                {
                    using (ZipFile zip = ZipFile.Read(file))
                    {
                        zip.ExtractAll(targetDir, ExtractExistingFileAction.OverwriteSilently);
                    }
                }
                else
                    File.Copy(file, Path.Combine(targetDir, Path.GetFileName(file)), true);
            }
            foreach (var directory in Directory.GetDirectories(sourceDir))
                Copy(directory, Path.Combine(targetDir, Path.GetFileName(directory)));
        }
        private void btUpdate_Click(object sender, EventArgs e)
        {
            Application.DoEvents();

            if (!Checker.IsProcessOpen(Checker.ServerConfg.Name))
            {
                btUpdate.Visible = false;

                btSkip.Visible = false;
                lbStatus.Visible = true;
                pbTotal.Visible = true;

                string RootPath = Application.StartupPath;
                string VersionPath = RootPath + "\\" + Checker.ServerConfg.Version + "\\";
                if (Directory.Exists(VersionPath))
                    Directory.Delete(VersionPath, true);

                Directory.CreateDirectory(VersionPath);
                ///if()

                pbTotal.Maximum = Checker.ServerConfg.Files.Count;
                ThreadPool.QueueUserWorkItem(a =>
                        {
                            Thread.Sleep(1000);
                            try
                            {
                                foreach (ServerConfigFile file in Checker.ServerConfg.Files)
                                {
                                    Application.DoEvents();
                                    RunOnUiThread(() =>
                                    {
                                        lbStatus.Text = string.Format("Downloading {0} - {1}Kb", file.Name, file.Size / 1000);
                                    });
                                    RunOnUiThread(() =>
                                    {
                                        pbTotal.Value++;

                                    });
                                    if (file.Name == "\\HiUpdateTools.Client.Win.exe" || file.Name == "\\Ionic.Zip.Reduced.dll" || file.Name == "\\edtFTPnet.dll")
                                    {
                                        continue;
                                    }
                                    Uri fileUri = new Uri(String.Format("{0}://{1}/{2}{3}.deploy", Checker.ClientConfg.ClientPathType, Checker.ClientConfg.ClientPath.TrimEnd("/".ToCharArray()), Checker.ServerConfg.Version, file.Name.Replace("\\", "/")));
                                    string localFilePath = RootPath + file.Name;
                                    if (File.Exists(localFilePath))
                                    {
                                        FileInfo info = new FileInfo(localFilePath);
                                        if (info.Length == file.Size && info.LastWriteTimeUtc == file.Date)
                                        {
                                            // Thread.Sleep();
                                            continue;
                                        }
                                    }

                                    if (file.Name.LastIndexOf("\\") != 0)
                                        Directory.CreateDirectory(VersionPath + file.Name.Substring(0, file.Name.LastIndexOf("\\") + 1));
                                    ///  IsBusy = true;
                                    Console.WriteLine("Downloading - {0}", file.Name);
                                    int TryCount = 0;
                                    byte[] fileData = null;
                                back:

                                    try
                                    {
                                        TryCount++;
                                        Task.Factory.StartNew(() =>
                                         {
                                             fileData = Checker.DownloadData(fileUri);
                                         })
                                         .Wait(((Convert.ToInt32(file.Size / 1000) / 4)+1) * 1000*2);
                                    }
                                    catch (Exception ex)
                                    {
                                        Checker.ResetFtp();


                                    }
                                    if (fileData == null && TryCount < 3)
                                        goto back;
                                    //WebHeaderCollection whc = Checker.Downloader.ResponseHeaders;
                                    //string contentLength = whc["Content-Length"];

                                    //int totalLength = (Int32.Parse(contentLength));

                                    //RunOnUiThread(() =>
                                    //{
                                    //    pbStatus.Maximum = totalLength;
                                    //});
                                    using (var newfile = File.Create(VersionPath + file.Name + ".deploy"))
                                    {



                                        //RunOnUiThread(() =>
                                        //{
                                        //    pbStatus.Value = (int)newfile.Length;
                                        //});
                                        newfile.Write(fileData, 0, fileData.Length);

                                    }


                                    //while (IsBusy)
                                    //   Thread.SpinWait(1);  

                                    Console.WriteLine("Download finish - {0}", file.Name);



                                }

                                RunOnUiThread(() =>
                                {
                                    lbStatus.Text = string.Format("Prepare run application...");
                                    pbTotal.Visible = false;
                                });
                                Copy(VersionPath, RootPath);
                                Directory.Delete(VersionPath, true);
                                // lbStatus.Text = "Updatuji aplikaci";
                                RunOnUiThread(() =>
                                {
                                    lbStatus.Text = string.Format("Runnnig application...");

                                });

                            }
                            catch (Exception ex)
                            {
                                RunOnUiThread(() =>
                            {
                                using (ErrorForm dialog = new ErrorForm())
                                {
                                    dialog.Error = ex;
                                    dialog.ShowDialog();


                                }
                            });
                            }
                            finally
                            {
                                RunOnUiThread(() =>
                                  {
                                      Program.AppMutex.ReleaseMutex();
                                      Checker.RunApplication();
                                      Application.Exit();

                                  });

                            }
                        });
            }
            else
            {

                Program.AppMutex.ReleaseMutex();
                Checker.RunApplication();
                Application.Exit();


            }

        }





        public UpdateChecker Checker { get; set; }

        private void UpdateForm_Load(object sender, EventArgs e)
        {
            try
            {
                if (Checker == null)
                {

                    Checker = new UpdateChecker(Program.Args[0], new Version(Program.Args[1]));
                    Checker.Check();
                }
                lbAplicationName.Text = Checker.ServerConfg.Name;
                lbVersion.Text = Checker.ServerConfg.Version;
                if (Checker != null)
                {
                    if (Checker.ClientConfg.AutoUpdate)
                    {
                        btUpdate_Click(sender, e);
                    }


                }
            }
            catch (Exception ex)
            {

                using (ErrorForm frm = new ErrorForm())
                {
                    frm.Error = ex;
                    frm.ShowDialog();
                }
                btSkip_Click(null, EventArgs.Empty);
            }

        }

        private void btSkip_Click(object sender, EventArgs e)
        {
            Checker.RunApplication();
            Application.Exit();
        }
    }
}
